package com.sakiko.audiobook.album.receiver;

import com.alibaba.fastjson.JSON;
import com.rabbitmq.client.Channel;
import com.sakiko.audiobook.album.service.TrackInfoService;
import com.sakiko.audiobook.common.rabbit.constant.MqConst;
import com.sakiko.audiobook.vo.album.TrackStatMqVo;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

/**
 * projectName: com.sakiko.audiobook.album.receiver
 *
 * @author: sakiko
 * time: 2025/10/6 3:48
 * description: 声音修改相关 (今天这里主要是针对 播放歌曲 添加次数修改做操作)
 */
@Component
public class TrackReceiver {

    @Autowired
    private TrackInfoService trackInfoService;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 监听更新声音的播放进度中对应修改 track_stat的服务消费
     *
     * @param msg
     * @param message
     * @param channel
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.ROUTING_TRACK_STAT_UPDATE, durable = "true", autoDelete = "false"),
            exchange = @Exchange(MqConst.EXCHANGE_TRACK),
            key = MqConst.ROUTING_TRACK_STAT_UPDATE
    ))
    public void trackStatUpdate(String msg, Message message, Channel channel) {
        try {
            // 接收消息并判断
            if (!StringUtils.isEmpty(msg)) {
                // 需要将消息重新转换为实体类 (发送 JSON.toJSONString())
                TrackStatMqVo trackStatMqVo = JSON.parseObject(msg, TrackStatMqVo.class);
                // 利用当时声明的业务编号防止消息重复消费，保证幂等性!
                Boolean isFirstConsume = redisTemplate.opsForValue().setIfAbsent(trackStatMqVo.getBusinessNo(), 1, 1, TimeUnit.MINUTES);
                try {
                    if (isFirstConsume) {
                        // 调用服务层方法更新数据
                        trackInfoService.trackStatUpdate(trackStatMqVo);
                    }
                } catch (Exception e) {
                    // 更新过程有毛病，删除redis中的 key，不然后续重发消费不了
                    redisTemplate.delete(trackStatMqVo.getBusinessNo());
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        // 消息确认
        try {
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

/* 关于消息的重试(本方法的属性修改无关紧要，这里没有channel.basicNack,但是可以想一下nack的处理)
1、可以配置springboot自动重发
spring:
  rabbitmq:
    listener:
      simple:
        acknowledge-mode: manual
        prefetch: 1
        retry:
          enabled: true        # 开启重试
          max-attempts: 3      # 最大重试3次（包括第一次）
          initial-interval: 2s # 每次重试间隔2秒
2、(这里现在没配置死信队列 -> 创建一个私信队列、监听，这个@Queue绑定死信队列 basicNack的requeue=false,死信队列当生产者用convertAndSend就可以，也可以定义变量判断重发次数)
3、直接 第三个参数(requeue) true回到队列消费，但是没抓做其他处理，可能循环如此导致cpu爆升 【生产环境不推荐，生产环境使用上面两种多做考虑】
 */